package protocol

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"strings"
)

type McPacket struct {
	Data []byte
}

type McStatusResponse struct {
	Version struct {
		Name string `json:"name"`
	} `json:"version"`

	Players struct {
		Max    int `json:"max"`
		Online int `json:"online"`
	} `json:"players"`

	Favicon string `json:"favicon"`
}

func (packet *McPacket) WriteTo(w io.Writer) (int64, error) {
	totalWritten := int64(0)

	n, err := WriteVarInt(w, len(packet.Data))
	totalWritten += n
	if err != nil {
		return totalWritten, err
	}

	n, err = io.Copy(w, bytes.NewReader(packet.Data))
	totalWritten += n
	if err != nil {
		return totalWritten, err
	}

	return totalWritten, nil
}

func (p *McPacket) ToMcStatusResponse() (*McStatusResponse, error) {
	response := &McStatusResponse{}

	r := bytes.NewReader(p.Data)
	pid, err := ReadVarInt(r)
	if err != nil {
		return nil, err
	}

	if pid != 0 {
		return nil, errors.New("trying to read Status Response from a packet with PID != 0")
	}

	jsonString, err := ReadString(r)
	if err != nil {
		return nil, err
	}
	//log.Printf("Read a json string: %s\n", jsonString)

	if err := json.NewDecoder(strings.NewReader(jsonString)).Decode(response); err != nil {
		return nil, err
	}

	return response, nil
}

func NewHandshakePacket(protocolVersion int, serverAddress string, serverPort uint16) (*McPacket, error) {
	var buffer bytes.Buffer

	if _, err := WriteVarInt(&buffer, 0); err != nil { // PID: 0
		return nil, err
	}

	if _, err := WriteVarInt(&buffer, protocolVersion); err != nil { // Protocol version
		return nil, err
	}

	if _, err := WriteString(&buffer, serverAddress); err != nil { // Server address
		return nil, err
	}

	if _, err := buffer.Write([]byte{byte(serverPort >> 8), byte(serverPort)}); err != nil { // Server port
		return nil, err
	}

	if _, err := WriteVarInt(&buffer, 1); err != nil { // Next state
		return nil, err
	}

	p := &McPacket{Data: buffer.Bytes()}

	return p, nil
}

func NewStatusPacket() (*McPacket, error) {
	var buffer bytes.Buffer

	if _, err := WriteVarInt(&buffer, 0); err != nil { // PID: 0
		return nil, err
	}

	p := &McPacket{Data: buffer.Bytes()}

	return p, nil
}

func ReadPacket(r io.Reader) (*McPacket, error) {
	length, err := ReadVarInt(r)
	if err != nil {
		return nil, err
	}

	var buffer bytes.Buffer
	if _, err := io.CopyN(&buffer, r, int64(length)); err != nil {
		return nil, err
	}

	p := &McPacket{Data: buffer.Bytes()}

	return p, nil
}
